//
// Created by 陈奕锟 on 2022/11/20.
//

#ifndef AUTOMATICTELLER_MESSAGE_HPP
#define AUTOMATICTELLER_MESSAGE_HPP

#endif //AUTOMATICTELLER_MESSAGE_HPP
#pragma once

#include <mutex>
#include <condition_variable>
#include <queue>
#include <memory>

namespace messaging
{
    struct message_base // * 消息基类
    {
        virtual ~message_base() = default;
    };

    template<typename Msg>
    struct wrapped_message : message_base   // * 每种消息都有特化类型
    {
        Msg contents;
        explicit wrapped_message(Msg const& i_contents)
            : contents(i_contents)
        {}
    };

    class queue // * 消息队列
    {
    private:
        std::mutex m;
        std::condition_variable c;
        std::queue< std::shared_ptr<message_base> > q;  // * 以私有队列储存，message_base类的共享指针

    public:
        template<typename T>
        void push(T const& msg)
        {
            std::lock_guard<std::mutex> lk(m);
            q.push( std::make_shared< wrapped_message<T> >(msg) );  // * 包装发布的消息，并储存相关的指针
            c.notify_all();
        }

        std::shared_ptr<message_base> wait_and_pop()
        {
            std::unique_lock<std::mutex> lk(m);
            c.wait(lk, [&] { return !q.empty(); }); // * 如果队列为空，就阻塞当前线程

            auto res = q.front();
            q.pop();

            return res;
        }
    };
}